home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / misc / pdflib / p_basic.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  13KB  |  527 lines

  1. /* p_basic.c
  2.  * Copyright (C) 1997-98 Thomas Merz. All rights reserved.
  3.  *
  4.  * PDFlib general routines
  5.  */
  6.  
  7. #include <stdlib.h>
  8. #include <time.h>
  9. #include <string.h>
  10.  
  11. #include "p_intern.h"
  12.  
  13. /* 
  14.  * The names arrays must be kept in sync with the corresponding
  15.  * enum types in pdf.h
  16.  */
  17. const char *pdf_filter_names[compression_count] = {
  18.     "", "LZWDecode", "RunLengthDecode", "CCITTFaxDecode",
  19.     "DCTDecode", "FlateDecode"
  20. };
  21.  
  22. const char *pdf_colorspace_names[colorspace_count] = {
  23.     "DeviceGray", "DeviceRGB", "DeviceCMYK", 
  24.     "CalGray", "CalRGB", "Lab", 
  25.     "Indexed", "Pattern", "Separation"
  26. };
  27.  
  28. const char *pdf_transition_names[] = {
  29.     "", "Split", "Blinds", "Box", "Wipe", "Dissolve", "Glitter", "R"
  30. };
  31.  
  32. void
  33. pdf_default_error_handler(int level, const char* fmt, va_list ap)
  34. {
  35.     switch (level) {
  36.     case PDF_INFO:
  37.         fprintf(stderr, "PDFlib note: ");
  38.         vfprintf(stderr, fmt, ap);
  39.         fputc('\n', stderr);
  40.         break;
  41.  
  42.     case PDF_WARN:
  43.         fprintf(stderr, "PDFlib warning: ");
  44.         vfprintf(stderr, fmt, ap);
  45.         fputc('\n', stderr);
  46.         break;
  47.  
  48.     case PDF_INTERNAL:
  49.         fprintf(stderr, "PDFlib internal error: ");
  50.         vfprintf(stderr, fmt, ap);
  51.         fputc('\n', stderr);
  52.         exit(88);
  53.         break;
  54.  
  55.     case PDF_FATAL:
  56.     default:
  57.         fprintf(stderr, "PDFlib fatal error: ");
  58.         vfprintf(stderr, fmt, ap);
  59.         fputc('\n', stderr);
  60.         exit(99);
  61.     }
  62. }
  63.  
  64. void
  65. pdf_error(PDF *p, int level, const char *fmt, ...)
  66. {
  67.     va_list ap;
  68.     va_start(ap, fmt);
  69.     (*p->info->error_handler)(level, fmt, ap);
  70.     va_end(ap);
  71. }
  72.  
  73. void *
  74. PDF_malloc(size_t size, char *caller)
  75. {
  76.     void *ret;
  77.  
  78.     if ((ret = calloc(size, 1)) == NULL) {
  79.     fprintf(stderr, "PDFLIB: couldn't allocate memory in %s!\n", caller);
  80.     }
  81.  
  82.     return ret;
  83. }
  84.  
  85. void
  86. PDF_free(void *mem)
  87. {
  88.     free(mem);
  89. }
  90.  
  91. PDF_info*
  92. PDF_get_info(void)
  93. {
  94.     PDF_info *info;
  95.  
  96.     info = (PDF_info *) PDF_malloc(sizeof(PDF_info), "PDF_get_info");
  97.  
  98.     info->binary_mode         = false;
  99.     info->required_compatibility= PDF1_1;
  100.  
  101.     /* Info dictionary entries */
  102.     info->Keywords        = NULL;
  103.     info->Subject        = NULL;
  104.     info->ModDate        = NULL;
  105.     info->Title            = NULL;
  106.     info->CreationDate        = NULL;
  107.     info->Creator        = NULL;
  108.     info->Producer        = NULL;
  109.     info->Author        = NULL;
  110.  
  111.     info->error_handler        = pdf_default_error_handler;
  112.  
  113.     info->fontpath        = PDF_DEFAULT_FONT_PATH;
  114.     return info;
  115. }
  116.  
  117. PDF *
  118. PDF_open(FILE *fp, PDF_info *info)
  119. {
  120.     time_t    timer;
  121.     struct tm    ltime;
  122.     PDF        *p;
  123.  
  124.     if (info == NULL)
  125.     return (PDF *) NULL;
  126.  
  127.     if ((p = (PDF *) PDF_malloc(sizeof(PDF), "PDF_open")) == NULL)
  128.     return (PDF *) NULL;
  129.  
  130.     p->fp        = fp;
  131.     p->info        = info;
  132.  
  133. #ifdef DEBUG
  134.     /* We override the caller's option for debugging! */
  135.     p->info->binary_mode         = true;
  136. #endif
  137.  
  138.     if (ftell(p->fp) == -1)
  139.     pdf_error(p, PDF_FATAL, "Problem with PDF output file!");
  140.  
  141.     (void) fputs("%PDF-1.1\n", p->fp);        /* Header */
  142.     /* write binary magic number for ASCII and binary files! */
  143.     (void) fputs("%\342\343\317\323\n", p->fp);
  144.  
  145.     p->info_id = pdf_begin_obj(p, NEW_ID);    /* Info object */
  146.  
  147.     pdf_begin_dict(p);
  148.     if(p->info->Keywords)
  149.     (void) fprintf(p->fp, "/Keywords (%s)\n", p->info->Keywords);
  150.     if(p->info->Subject)
  151.     (void) fprintf(p->fp, "/Subject (%s)\n", p->info->Subject);
  152.     if(p->info->Title)
  153.     (void) fprintf(p->fp, "/Title (%s)\n", p->info->Title);
  154.     if(p->info->Creator)
  155.     (void) fprintf(p->fp, "/Creator (%s)\n", p->info->Creator);
  156.     if(p->info->Author)
  157.     (void) fprintf(p->fp, "/Author (%s)\n", p->info->Author);
  158.  
  159.     time(&timer);
  160.     ltime = *localtime(&timer);
  161.     (void) fprintf(p->fp, "/CreationDate (D:%04d%02d%02d%02d%02d%02d)\n",
  162.         ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
  163.         ltime.tm_hour, ltime.tm_min, ltime.tm_sec);
  164.  
  165.     (void) fprintf(p->fp,"/Producer (%s)\n", PDFLIB_VERSION);
  166.     pdf_end_dict(p);
  167.     pdf_end_obj(p);
  168.  
  169.     p->current_page    = 0;
  170.     p->outlines_id    = 0;
  171.     p->pages_id        = pdf_alloc_id(p);
  172.     p->root_id        = pdf_alloc_id(p);
  173.     p->open_outlines    = 0;
  174.     p->image_number    = 0;
  175.     p->outline_count    = 0;
  176.  
  177.     /* HACK, should use font cache */
  178.     p->current_font    = (pdf_font *) PDF_malloc(sizeof(pdf_font), "PDF_open");
  179.  
  180.     return p;
  181. }
  182.  
  183. /* separate finalize routine requested by Just van Rossum
  184.  * for supporting the Python binding
  185.  */
  186.  
  187. void
  188. pdf_finalize(PDF *p)
  189. {
  190.     fclose(p->fp);
  191.  
  192.  
  193.     /* HACK, should use font cache */
  194.     PDF_free((void *)p->current_font);
  195.  
  196.     PDF_free((void *)p->info);
  197.     PDF_free((void *)p);
  198.     /* TODO: free item list */
  199. }
  200.  
  201. void
  202. PDF_close(PDF *p)
  203. {
  204.     long    pos;
  205.     int        page;
  206.     id        i;
  207.  
  208.     if (p->current_page == 0 ) {        /* avoid empty document */
  209.     PDF_begin_page(p, 100.0, 100.0);    /* arbitrary page size */
  210.     PDF_end_page(p);
  211.     pdf_error(p, PDF_WARN, "Empty document!");
  212.     }
  213.  
  214.     p->open_action = pdf_begin_obj(p, NEW_ID);
  215.     (void) fprintf(p->fp,"[ %ld 0 R /Fit ]\n", p->pages[1]);
  216.     pdf_end_obj(p);
  217.  
  218.     pdf_put_fonts(p);                /* Font objects */
  219.  
  220.     pdf_begin_obj(p, p->pages_id);    /* root Pages object */
  221.     pdf_begin_dict(p);
  222.     (void) fputs("/Type /Pages\n", p->fp);
  223.     (void) fprintf(p->fp,"/Count %d\n", p->current_page);
  224.  
  225.     (void) fputs("/Kids [", p->fp);
  226.     for (page = 1; page <= p->current_page; page++) {
  227.     (void) fprintf(p->fp,"%ld 0 R", p->pages[page]);
  228.     (void) fputs(page % 6 ? " " : "\n", p->fp);
  229.     }
  230.     (void) fputs("]\n", p->fp);
  231.  
  232.     pdf_end_dict(p);
  233.     pdf_end_obj(p);
  234.  
  235.     pdf_begin_obj(p, p->root_id);        /* Catalog or Root object */
  236.     pdf_begin_dict(p);
  237.     (void) fputs("/Type /Catalog\n", p->fp);
  238.  
  239.     /* make the first page fit in the window */
  240.     (void) fprintf(p->fp,"/OpenAction %ld 0 R\n", p->open_action);
  241.  
  242.     /* open outlines if the document has any */
  243.     if (p->outline_count > 0)
  244.     (void) fputs("/PageMode /UseOutlines\n", p->fp);
  245.  
  246.                             /* Pages object */
  247.     (void) fprintf(p->fp,"/Pages %ld 0 R\n", p->pages_id);
  248.     if (p->outlines_id != 0)
  249.     (void) fprintf(p->fp,"/Outlines %ld 0 R\n", p->outlines_id);
  250.  
  251.     pdf_end_dict(p);
  252.     pdf_end_obj(p);
  253.  
  254.     pdf_write_outlines(p);
  255.  
  256.     /* don't write any objects after this check! */
  257.     for (i = 1; i <= p->currentobj; i++) {
  258.     if (p->file_offset[i] == BAD_ID) {
  259.         pdf_error(p, PDF_WARN, 
  260.             "Object %ld allocated but not used (dummy inserted)!", i);
  261.         pdf_begin_obj(p, i);
  262.         pdf_end_obj(p);
  263.     }
  264.     }
  265.  
  266.     pos = ftell(p->fp);                    /* xref table */
  267.     (void) fputs("xref\n", p->fp);
  268.     (void) fprintf(p->fp,"0 %ld\n", p->currentobj + 1);
  269.     (void) fputs("0000000000 65535 f \n", p->fp);
  270.     for (i = 1; i <= p->currentobj; i++) {
  271.     (void) fprintf(p->fp,"%010ld 00000 n \n", p->file_offset[i]);
  272. #ifdef FOOBAR
  273.     (void) fprintf(p->fp,"%010ld 00000 n\n", p->file_offset[i]);
  274. #endif
  275.     }
  276.  
  277.     (void) fputs("trailer\n", p->fp);
  278.     pdf_begin_dict(p);
  279.     (void) fprintf(p->fp,"/Size %ld\n", p->currentobj + 1);
  280.     (void) fprintf(p->fp,"/Info %ld 0 R\n", p->info_id);
  281.     (void) fprintf(p->fp,"/Root %ld 0 R\n", p->root_id);
  282.     pdf_end_dict(p);
  283.     (void) fputs("startxref\n", p->fp);
  284.     (void) fprintf(p->fp,"%ld\n", pos);
  285.     (void) fputs("%%EOF\n", p->fp);
  286.  
  287.     pdf_finalize(p);
  288.  
  289. }
  290.  
  291. void
  292. pdf_begin_contents_section(PDF *p)
  293. {
  294.     if (p->contents != c_none)
  295.     return;
  296.  
  297.     if (p->next_content > MAX_CONTENTS)
  298.     pdf_error(p, PDF_FATAL, "Too many content sections on page (%ld)!",
  299.             p->contents);
  300.  
  301.                                 /* Contents object */
  302.     p->contents_ids[p->next_content] = pdf_begin_obj(p, NEW_ID);
  303.     p->contents    = c_stream;
  304.     pdf_begin_dict(p);
  305.     p->contents_length = pdf_alloc_id(p);
  306.     (void) fprintf(p->fp,"/Length %ld 0 R\n", p->contents_length);
  307.     pdf_end_dict(p);
  308.  
  309.     pdf_begin_stream(p);
  310.     p->start_contents_pos = ftell(p->fp);
  311.     p->next_content++;
  312. }
  313.  
  314. void
  315. pdf_end_contents_section(PDF *p)
  316. {
  317.     long length;
  318.  
  319.     if (p->contents == c_none)
  320.     return;
  321.  
  322.     pdf_end_text(p);
  323.     p->contents = c_none;
  324.  
  325.     length = ftell(p->fp) - p->start_contents_pos;
  326.     pdf_end_stream(p);
  327.     pdf_end_obj(p);
  328.  
  329.     pdf_begin_obj(p, p->contents_length);    /* Length object */
  330.     (void) fprintf(p->fp,"%ld\n", length);
  331.     pdf_end_obj(p);
  332. }
  333.  
  334. void
  335. PDF_begin_page(PDF *p, float height, float width)
  336. {
  337.     if (++(p->current_page) > MAX_PAGES)
  338.     pdf_error(p, PDF_FATAL, "Too many pages in document (%d)!",
  339.         p->current_page);
  340.  
  341.     p->pages[p->current_page]    = pdf_alloc_id(p);
  342.  
  343.     p->height    = height;
  344.     p->width    = width;
  345.  
  346.     p->next_content = 0;
  347.     p->contents = c_none;
  348.     pdf_begin_contents_section(p);
  349. }
  350.  
  351. void
  352. PDF_end_page(PDF *p)
  353. {
  354.     pdf_item    *i;
  355.     int        index = 0;
  356.  
  357.     pdf_end_contents_section(p);
  358.  
  359.     pdf_begin_obj(p, p->pages[p->current_page]);    /* Page object */
  360.     pdf_begin_dict(p);
  361.     (void) fputs("/Type /Page\n", p->fp);
  362.     (void) fprintf(p->fp,"/Parent %ld 0 R\n", p->pages_id);
  363.  
  364.     p->res_id = pdf_alloc_id(p);
  365.     (void) fprintf(p->fp,"/Resources %ld 0 R\n", p->res_id);
  366.  
  367.     (void) fprintf(p->fp,"/MediaBox [0 0 %g %g]\n", p->height, p->width);
  368.  
  369.     if (p->duration > 0)
  370.     (void) fprintf(p->fp, "/D %s\n", pdf_float(p->duration));
  371.  
  372.     if (p->transition != trans_none) {
  373.     (void) fputs("/Trans ", p->fp);
  374.     pdf_begin_dict(p);
  375.         (void) fprintf(p->fp, "/S /%s",
  376.                     pdf_transition_names[p->transition]);
  377.     pdf_end_dict(p);
  378.     }
  379.  
  380.     (void) fputs("/Contents [", p->fp);
  381.     for (index = 0; index < p->next_content; index++) {
  382.     (void) fprintf(p->fp,"%ld 0 R", p->contents_ids[index]);
  383.     (void) fputs(index+1 % 6 ? " " : "\n", p->fp);
  384.     }
  385.     (void) fputs("]\n", p->fp);
  386.  
  387.     pdf_end_dict(p);
  388.     pdf_end_obj(p);
  389.  
  390.     pdf_begin_obj(p, p->res_id);            /* Resource object */
  391.     pdf_begin_dict(p);
  392.  
  393.     (void) fputs("/ProcSet [/PDF", p->fp);        /* ProcSet resources */
  394.     if ( p->res.procset & ImageB)
  395.     (void) fputs(" /ImageB", p->fp);
  396.     if ( p->res.procset & ImageC)
  397.     (void) fputs(" /ImageC", p->fp);
  398.     if ( p->res.procset & ImageI)
  399.     (void) fputs(" /ImageI", p->fp);
  400.     if ( p->res.procset & Text)
  401.     (void) fputs(" /Text", p->fp);
  402.     (void) fputs("]\n", p->fp);
  403.  
  404.     if (p->res.font != (pdf_item *) NULL)
  405.     {
  406.     (void) fputs("/Font ", p->fp);            /* Font resources */
  407.  
  408.     pdf_begin_dict(p);
  409.         for(i = p->res.font, index = 0; i != (pdf_item *) NULL; i = i->next)
  410.         {
  411.         (void) fprintf(p->fp,"/F%d %ld 0 R\n", index++, i->obj_id);
  412.         }
  413.     pdf_end_dict(p);
  414.     }
  415.  
  416.     if (p->res.xobject != (pdf_item *) NULL)
  417.     {
  418.     (void) fputs("/XObject ", p->fp);        /* XObject resources */
  419.  
  420.     pdf_begin_dict(p);
  421.         for(i = p->res.xobject, index = 0; i != (pdf_item *) NULL; i = i->next)
  422.         {
  423.         (void) fprintf(p->fp,"/I%d %ld 0 R\n", index++, i->obj_id);
  424.         }
  425.     pdf_end_dict(p);
  426.     }
  427.  
  428.     pdf_end_dict(p);
  429.     pdf_end_obj(p);
  430. }
  431.  
  432. /* set page display duration for current and future pages */
  433. void
  434. PDF_set_duration(PDF *p, float t)
  435. {
  436.     p->duration = t;
  437. }
  438.  
  439. /* set transition mode for current and future page */
  440. void
  441. PDF_set_transition(PDF *p, PDF_transition t)
  442. {
  443.     if (t >= transition_count) {
  444.     pdf_error(p, PDF_WARN, "Illegal page transition value");
  445.     return;
  446.     }
  447.     p->transition = t;
  448. }
  449.  
  450. id
  451. pdf_begin_obj(PDF *p, id obj_id)
  452. {
  453.     if (obj_id == NEW_ID)
  454.     obj_id = pdf_alloc_id(p);
  455.  
  456.     p->file_offset[obj_id] = ftell(p->fp); 
  457.     (void) fprintf(p->fp, "%ld 0 obj\n", obj_id);
  458.     return obj_id;
  459. }
  460.  
  461. id
  462. pdf_alloc_id(PDF *p)
  463. {
  464.     p->currentobj++;
  465.     if (p->currentobj >= MAX_ID)
  466.     pdf_error(p, PDF_FATAL, "Too many objects (%ld)!", p->currentobj);
  467.  
  468.     /* only needed for verifying obj table in PDF_close() */
  469.     p->file_offset[p->currentobj] = BAD_ID;
  470.  
  471.     return p->currentobj;
  472. }
  473.  
  474. pdf_item *
  475. pdf_add_res_font(PDF *p, char *basename)
  476. {
  477.     pdf_item *item, **last_item;
  478.  
  479.     last_item = &p->res.font;
  480.  
  481.     for (item = p->res.font; item != (pdf_item *) NULL; item = item->next)
  482.     {
  483.     if (!strcmp(item->basename, basename))
  484.         return item;            /* resource already listed */
  485.     last_item = &item->next;
  486.     }
  487.  
  488.     *last_item    = (pdf_item *) PDF_malloc(sizeof(pdf_item), "pdf_add_res_font");
  489.     item    = *last_item;
  490.     item->name    = (char *) PDF_malloc(6, "pdf_add_res_font");
  491.  
  492.     sprintf(item->name, "/F%d", p->font_number);
  493.     p->font_number++;
  494.  
  495.     item->basename= (char *) PDF_malloc(strlen(basename)+1, "pdf_add_res_font");
  496.     strcpy(item->basename, basename);
  497.     item->obj_id    = pdf_alloc_id(p);
  498.     item->next        = (pdf_item *) NULL;
  499.  
  500.     *last_item        = item;
  501.  
  502.     return item;
  503. }
  504.  
  505. void
  506. pdf_add_res_xobject(PDF *p, id xobj_id)
  507. {
  508.     pdf_item *item, **last_item;
  509.  
  510.     last_item = &p->res.xobject;
  511.  
  512.     for (item = p->res.xobject; item != (pdf_item *) NULL; item = item->next)
  513.     last_item = &item->next;
  514.  
  515.     *last_item    = (pdf_item *) PDF_malloc(sizeof(pdf_item), "pdf_add_res_xobject");
  516.     item    = *last_item;
  517.     item->name    = (char *) PDF_malloc(6, "pdf_add_res_xobject");
  518.  
  519.     sprintf(item->name, "/I%d", p->xobject_number);
  520.     p->xobject_number++;
  521.  
  522.     item->obj_id    = xobj_id;
  523.     item->next        = (pdf_item *) NULL;
  524.  
  525.     *last_item        = item;
  526. }
  527.